package com.example.backend.repository.spec;

import com.example.backend.domain.entity.Notification;
import com.example.backend.domain.enums.NotificationChannel;
import com.example.backend.domain.enums.NotificationPriority;
import com.example.backend.domain.enums.NotificationStatus;
import com.example.backend.domain.enums.NotificationType;
import com.example.backend.dto.NotificationFilter;
import org.springframework.data.jpa.domain.Specification;

import java.time.Instant;

/**
 * 通知查询规格构建器
 */
public class NotificationSpecifications {
    
    public static Specification<Notification> withFilter(NotificationFilter filter) {
        if (filter == null) {
            return (root, query, cb) -> cb.conjunction();
        }
        
        Specification<Notification> spec = (root, query, cb) -> cb.conjunction();
        
        // 用户ID
        spec = spec.and(hasUserId(filter.getUserId()));
        
        // 通知类型
        spec = spec.and(hasType(filter.getType()));
        
        // 通知通道
        spec = spec.and(hasChannel(filter.getChannel()));
        
        // 通知状态
        spec = spec.and(hasStatus(filter.getStatus()));
        
        // 通知优先级
        spec = spec.and(hasPriority(filter.getPriority()));
        
        // 关键词搜索
        spec = spec.and(hasKeyword(filter.getKeyword()));
        
        // 创建时间范围
        spec = spec.and(createdFrom(filter.getCreatedFrom()));
        spec = spec.and(createdTo(filter.getCreatedTo()));
        
        // 阅读时间范围
        spec = spec.and(readFrom(filter.getReadFrom()));
        spec = spec.and(readTo(filter.getReadTo()));
        
        // 是否有操作链接
        spec = spec.and(hasActionUrl(filter.getHasActionUrl()));
        
        return spec;
    }
    
    public static Specification<Notification> hasUserId(Long userId) {
        return (root, query, cb) -> userId == null ? cb.conjunction() : cb.equal(root.get("userId"), userId);
    }
    
    public static Specification<Notification> hasType(NotificationType type) {
        return (root, query, cb) -> type == null ? cb.conjunction() : cb.equal(root.get("type"), type);
    }
    
    public static Specification<Notification> hasChannel(NotificationChannel channel) {
        return (root, query, cb) -> channel == null ? cb.conjunction() : cb.equal(root.get("channel"), channel);
    }
    
    public static Specification<Notification> hasStatus(NotificationStatus status) {
        return (root, query, cb) -> status == null ? cb.conjunction() : cb.equal(root.get("status"), status);
    }
    
    public static Specification<Notification> hasPriority(NotificationPriority priority) {
        return (root, query, cb) -> priority == null ? cb.conjunction() : cb.equal(root.get("priority"), priority);
    }
    
    public static Specification<Notification> hasKeyword(String keyword) {
        return (root, query, cb) -> {
            if (keyword == null || keyword.trim().isEmpty()) {
                return cb.conjunction();
            }
            String pattern = "%" + keyword.trim() + "%";
            return cb.or(
                cb.like(cb.lower(root.get("title")), pattern.toLowerCase()),
                cb.like(cb.lower(root.get("content")), pattern.toLowerCase())
            );
        };
    }
    
    public static Specification<Notification> createdFrom(Instant from) {
        return (root, query, cb) -> from == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("createdAt"), from);
    }
    
    public static Specification<Notification> createdTo(Instant to) {
        return (root, query, cb) -> to == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("createdAt"), to);
    }
    
    public static Specification<Notification> readFrom(Instant from) {
        return (root, query, cb) -> from == null ? cb.conjunction() : cb.greaterThanOrEqualTo(root.get("readAt"), from);
    }
    
    public static Specification<Notification> readTo(Instant to) {
        return (root, query, cb) -> to == null ? cb.conjunction() : cb.lessThanOrEqualTo(root.get("readAt"), to);
    }
    
    public static Specification<Notification> hasActionUrl(Boolean hasActionUrl) {
        return (root, query, cb) -> {
            if (hasActionUrl == null) {
                return cb.conjunction();
            }
            if (hasActionUrl) {
                return cb.isNotNull(root.get("actionUrl"));
            } else {
                return cb.isNull(root.get("actionUrl"));
            }
        };
    }
    
    public static Specification<Notification> isUnread() {
        return (root, query, cb) -> cb.equal(root.get("status"), NotificationStatus.UNREAD);
    }
    
    public static Specification<Notification> isUrgent() {
        return (root, query, cb) -> cb.or(
            cb.equal(root.get("priority"), NotificationPriority.URGENT),
            cb.equal(root.get("priority"), NotificationPriority.HIGH)
        );
    }
}
